React 在 16.3 版新增了一些新的生命週期方法,並開始逐漸廢棄一些舊方法,舊方法就是前一篇提過的componentWillMount()componentWillReceiveProps()componentWillUpdate()
新增的生命週期方法則是以下這幾個getDerivedStateFromPropsgetSnapshotBeforeUpdate
這一篇會針對整個生命週期和新版方法做整理。
constructor(props) 並生成實例, props 就是元件的父層傳遞來的參數。同時元件也會藉由 super() 去繼承一些 React.Component 的屬性和方法。如下面的範例, Input 元件中的 constructor(props),props 裡面的參數就是 Form 傳入的參數,而使用 super() 後,this 會指向 Input 本身。不過使用 constructor() 的麻煩就是你的屬性、函式都得在裡面定義。在一些框架中如 create-react-app 中是可以在 class 中直接定義屬性和函式而不必透過 constructor()。class Form extends React.Component {
state = {
value: '123'
}
onEditer (value) {
this.setState({value})
}
render () {
const { value } = this.state
return <div>
{value}
<Input value={value} onEditer={this.onEditer.bind(this)} />
</div>
}
}
class Input extends React.Component {
constructor (props) {
super() // 改變 this 的指向為這個元件
console.log(props) // props 就是 Form 元件傳進來的物件,裏面包含了 value、
}
render () {
const { onEditer } = this.props;
return <div>
<input type="text" onChange={e => onEditer(e.target.value)} />
</div>
}
}
constructor() 執行完畢後就會接著執行 getDerivedStateFromProps(),或者是元件有更新時,像是 props、state 更新,或者 forceUpdate() 執行,都會觸發這個方法。getDerivedStateFromProps() 是一個靜態方法,必須搭配 static 使用,它接受兩個參數,props、state,我們可以透過這個方法,去監聽這兩個參數,執行一些事情。getDerivedStateFromProps() 最後必須返回一個物件或是 null 值,如果返回物件,則依照物件內的屬性來更新 static。class Form extends React.Component {
state = {
value: 'leo'
}
onEditer (value) {
this.setState({value})
}
render () {
const { value } = this.state
return <div>
{value}
<Input value={value} onEditer={this.onEditer.bind(this)} />
</div>
}
}
class Input extends React.Component {
state = {
value: 'jack'
}
static getDerivedStateFromProps(props, state) {
if (props.value !== state.value) {
return {
value: props.value,
age: 26 //這邊新增一個 age 屬性,也會增加在 state 裡面
}
}
return null
}
render () {
console.log(this.state) // value: leo, age: 26
const { onEditer, value } = this.props;
return <div>
<input type="text" value={value} onChange={e => onEditer(e.target.value)} />
</div>
}
}
getDerivedStateFromProps() 執行完後,就接著執行 render 渲染整個元件。render 執行完後,表示我們已經有了整個 DOM 結構,這時候才輪到 componentDidMount 執行,而且只會在整個結構第一次渲染完成的這一次執行。componentDidMount 沒有任何參數,一般會在這個方法中去執行數據的請求。class UserProfile extends React.Component {
state = {
user: null
}
//在 componentDidMount 中進行非同步請求,並更新 state
async componentDidMount() {
const user = await fetch('/api/user').then(res => json());
this.setState({ user })
}
render () {
const { user = {} } = this.state;
return <div>
name: {user.name}
</div>
}
}
props、state 更新,或者 forceUpdate() 執行,都會觸發這個方法。shouldComponentUpdate() 接在 getDerivedStateFromProps(props, state) 之後執行,主要是藉由返回 Boolean 來判斷是否更新元件,避免一些不必要的更新。不過 React 官方不建議使用這個方法,而是建議使用 PureComponent,因為 PureComponent 也會避免不必要的更新。class UserProfile extends React.Component {
state = {
name: 'leo',
age: 20
}
changeVlue (state) {
return new Promise((resolve) => {
this.setState(state, resolve)
})
}
async changeData () {
const { age } = this.state
await this.changeVlue({age: age + 1})
}
shouldComponentUpdate () {
if (this.state.age > 26) { //當 age 大於 26,return false,停止更新
return false
}
return true
}
render () {
const { name, age } = this.state;
return <div>
{name} {age} 歲
<button onClick={this.changeData.bind(this)}>+1</button>
</div>
}
}
getSnapshotBeforeUpdate 是在 render 執行後,DOM 和 refs 更新前所做的事情,這可以讓我們在 DOM 變化前獲取一些訊息,例如畫面滾動之類的。如果在 getSnapshotBeforeUpdate 中返回值,生命週期會讓這個值作為參數傳遞給 componentDidUpdate()。props(prevProps)、更新前的 state(prevState)、以及 getSnapshotBeforeUpdate 返回的參數。componentWillMount() 是卸載階段唯一的方法,是在元件卸載前執行,我們可以在這邊處理一些不必在執行的功能,避免過度使用記憶體,例如計時器功能。componentDidCatch() 是在元件有錯誤時候會執行。defaultProps 用於定義 props 的默認屬性,可以用在定義 undefined 的 props,但不適用於 null。有分外部定義及內部定義兩種,外部定義用法如下,利用 compnentName.defaultProps 來定義默認屬性,當沒有外部屬性傳入,就使用默認屬性。class Form extends React.Component {
state = {
value: 'leo'
}
onEditer (value) {
this.setState({value})
}
render () {
const { title } = this.props //'測試用 input'
const { value } = this.state
return <div>
{value}
{title}
<Input value={value} onEditer={this.onEditer.bind(this)} />
</div>
}
}
// 外部定義 default
Form.defaultProps = {
title: '測試用 input'
}
內部定義則是直接使用 static defaultProps 來定義
class Form extends React.Component {
state = {
value: 'leo'
}
static defaultProps = { //由於 defaultProps 是靜態方法,必須搭配 static 使用
title: '默認 props'
}
onEditer (value) {
this.setState({value})
}
render () {
const { title } = this.props
const { value } = this.state
return <div>
{value}
{title}
<Input value={value} onEditer={this.onEditer.bind(this)} />
</div>
}
}
當內部外部都有定義 defaultProps 時候,只會執行外部定義,而會忽略內部定義。
2. forceUpdate()forceUpdate() 這個方法會強制渲染 React 元件,包含子元件也會重新渲染,使用方式是直接調用,如下
class App extends React.Component {
componentDidMount () {
this.forceUpdate();
}
}
這一篇我們整理了新版 React 生命週期方法,到這篇為止,算是把 React 中的一些基礎概念整理完畢,下一篇開始,將會進行一些實作練習。